#include "bV2.hh"
#include <SDL/SDL.h>
#include <SDL/sge.h>

using namespace std;
using boost::optional;

SDL_Surface *scr;
bool quit = false;

const char *program[] = {
  "100  PRINT \"Hello!\"",
  "110  LET gray = 0",
  "120  LET t = 0",
  "130  LET t2 = 1.41",
  "9998  LIST",
  "9999  END",
  "10000  REM run every frame from here",
  "10010  PRINT \"deltasec = \" deltasec",
  "10100  LET t = t + deltasec",
  "10110  LET t2 = t2 + 2 * deltasec",
  "10120  LET gray = COS ( t ) / 30 + 0.34",
  "10130  LET x = COS ( t ) * 200 + 320",
  "10140  LET y = COS ( t2 ) * 100 + 200",
  "10200  POKE t , t * 125",
  NULL
};

class MyBasic : public Basic {
protected:
  virtual void exec_poke2(FloatType addr, FloatType val) {
    unsigned int pos = static_cast<unsigned int>(addr);

    sge_PutPixel(scr, pos % scr->w, 3, static_cast<Uint32>(val));
  }

public:
  MyBasic() {
    unsigned short lineno;
    string tmp;

    for(const char **prg = program; *prg; ++prg) {
      istringstream line(*prg);
      line >> lineno;
      getline(line, tmp);
      TokenListType tokens(tokenise(default_keywords, tmp));
      add_line(lineno, tokens);      
    }
  }
};

int main() {
  SDL_Event event;
  MyBasic basic;
  Uint32 last_ticks, now_ticks;
  float deltasec;
  SDL_Rect dstrect;

  try {
    assert(SDL_Init(SDL_INIT_VIDEO) == 0);
    scr = SDL_SetVideoMode(640, 400, 8, SDL_HWSURFACE|SDL_ANYFORMAT|SDL_DOUBLEBUF);
    assert(scr);
    SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); //Ignore all mouse movements...
    last_ticks = SDL_GetTicks();
    basic.run();
    while(!quit) {
      now_ticks = SDL_GetTicks();
      deltasec = (now_ticks - last_ticks) / 1000.0f;
      basic.var_float("deltasec") = deltasec;
      printf("display: ticks = %lu delta = %10.8e\n", (unsigned long)now_ticks, deltasec);
      //
      while(SDL_PollEvent(&event) == 1 && quit == 0) {
        switch(event.type) {
        case SDL_QUIT:
          quit = true;
          break;
        case SDL_MOUSEBUTTONDOWN:
        case SDL_MOUSEBUTTONUP:
          printf("button=%d state=%d x=$%04hX y=$%04hX\n", event.button.button, event.button.state, event.button.x, event.button.y);
          break;
        case SDL_KEYDOWN:
        case SDL_KEYUP:
          printf("state=%d sym=$%04X\n", event.key.state, event.key.keysym.sym);
          break;
        default:
          printf("event.type = $%x\n", (unsigned int)event.type);
        }
      }
      basic.run(10000);
      float f = basic.var_float("gray");
      dstrect.x = 0;
      dstrect.y = 5;
      dstrect.w = scr->w;
      dstrect.h = scr->h;
      SDL_FillRect(scr, &dstrect, SDL_MapRGB(scr->format, 255 * f, 255 * f, 255 * f));
      dstrect.x = basic.var_float("x");
      dstrect.y = basic.var_float("y");
      dstrect.w = 10;
      dstrect.h = 10;
      SDL_FillRect(scr, &dstrect, SDL_MapRGB(scr->format, 225, 0, 0));
      SDL_Flip(scr);
      //
      last_ticks = now_ticks;
      if(deltasec < 0.005f) SDL_Delay(5);
    }

  }
  catch(const Basic::Error &error) {
    cout << "Error in line: " << basic.get_current_line_no() << endl;
    const Token *tok = basic.get_current_token();
    cerr << "Error '" << error.what() << "' at ";
    if(tok) 
      cerr << "token '" << tok->str() << "'!";
    else
      cerr << "end of line!";
    cerr << endl;
  }
  return 0;
}
